#pragma once

#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;

namespace cr
{
    const string pathname = "/home/cr/git/ProcessTalk/ShareMem/";
    const int proj_id = 20040712;
    int size = 4096; // 字节为单位

    class ShM
    {
    private:
        key_t _keyid; // 表示共享内存的唯一标识符
        int _shmid;   //
        char *_start; // 起始地址位置

    public:
        key_t getkey()
        {
            _keyid = ftok(pathname.c_str(), proj_id);
            if (_keyid == -1)
            {
                cout << "errno = " << errno << ",strerrno = " << strerror(errno) << endl;
                exit(1);
            }
            return _keyid;
        }

        bool creatshm()
        {
            // IPC_EXCL保证创建的是全新的共享内存，然后就是共享内存访问权限
            _shmid = shmget(_keyid, size, IPC_CREAT | IPC_EXCL | 0664);
            // 选项相当于没有就创建，有就返回错误
            if (_shmid == -1)
            {
                cout << "errno = " << errno << ",strerrno = " << strerror(errno) << endl;
                exit(1);
            }
            return true;
        }

        bool getshm()
        {
            _shmid = shmget(_keyid, size, IPC_CREAT | 0664); // 选项相当于没有就创建，有就返回shmid
            if (_shmid == -1)
            {
                cout << "errno = " << errno << ",strerrno = " << strerror(errno) << endl;
                exit(1);
            }
            return true;
        }

        bool shmatway()
        {
            _start = (char *)shmat(_shmid, nullptr, 0);
            // 第二个参数表示将共享内存挂载到地址空间的指定地址处,返回虚拟地址起始位置
            if (_start == (char *)-1)
            {
                cout << "errno = " << errno << ",strerrno = " << strerror(errno) << endl;
                exit(1);
            }
            return true;
        }

        bool destroyShm()
        {
            shmdt(_start); // 将共享内存段从调用进程的地址空间中分离（解除映射）

            // 删除共享内存段
            if (shmctl(_shmid, IPC_RMID, NULL) < 0)
            {
                perror("shmctl");
                return -1;
            }
            return true;
        }

        char *GetBeginPtr()
        {
            return _start;
        }
    };
}